﻿
Imports System.Reflection
Imports std
Imports centrosphere
Imports centrosphere.job
Imports centrosphere.job.storage
Imports command = centrosphere.job.storage.command

Partial Public Class storageJobRedundanceDistributor
    Private Function verify_aggregate(ByVal targetJobs() As indexedJob,
                                      ByVal inputJob As ijob,
                                      ByVal compare As compare_delegate,
                                      ByVal sync As void(Of [set](Of UInt32))) As Boolean
        assert(Not sync Is Nothing)
        Dim succ_indexes As [set](Of UInt32) = Nothing
        If redundance_compare_aggregate(targetJobs, inputJob, compare, succ_indexes:=succ_indexes) Then
            assert(succ_indexes.size() <= targetJobs.Length())
            If succ_indexes.size() < targetJobs.Length() AndAlso
               succ_indexes.size() > 0 Then
                sync(succ_indexes)
            End If
            Return True
        Else
            Return False
        End If
    End Function

    Private Function sync_modify_aggregate(ByVal compare As compare_delegate) As aggregate_delegate
        Return Function(targetJobs() As indexedJob, inputJob As ijob) As Boolean
                   Return verify_aggregate(targetJobs,
                                           inputJob,
                                           compare,
                                           Sub(ByRef i) sync_modify(inputJob, i))
               End Function
    End Function

    Private Function sync_read_modify_aggregate(ByVal compare As compare_delegate) As aggregate_delegate
        Return Function(targetJobs() As indexedJob, inputJob As ijob) As Boolean
                   Return verify_aggregate(targetJobs,
                                           inputJob,
                                           compare,
                                           Sub(ByRef i) sync_read_modify(storageJob(inputJob).key, i))
               End Function
    End Function

    Private ReadOnly all_aggregators() As aggregate_delegate = Nothing

    Private Function invoker(Of T)(ByVal name As String, ByVal suffix As String) As _do(Of T)
        Return Function() As T
                   assert(Not isemptystring(name))
                   assert(Not isemptystring(suffix))
                   Dim rtn As invoker(Of T) = Nothing
                   rtn = New invoker(Of T)(
                                      Me,
                                      BindingFlags.NonPublic Or BindingFlags.Instance Or BindingFlags.Static,
                                      strcat(name, suffix))
                   assert(rtn.valid())
                   Return +rtn
               End Function
    End Function

    Private Shared Function list_aggregate(ByVal targetJobs() As indexedJob, ByVal inputJob As ijob) As Boolean
        Return vs_intersect_aggregate(targetJobs, inputJob)
    End Function

    Private Function initial_all_aggregators() As aggregate_delegate()
        Dim rtn() As aggregate_delegate = Nothing
        ReDim rtn(storage.count - 1)
        storage.traversal(Sub(name As String, cmd As command, index As Int64)
                              assert(Not isemptystring(name))
                              assert(rtn(index) Is Nothing)
                              Dim cmp As _do(Of compare_delegate) =
                                            invoker(Of compare_delegate)(name, "_compare")
                              Dim aggregate As _do(Of aggregate_delegate) =
                                            invoker(Of aggregate_delegate)(name, "_aggregate")
                              Dim [set] As void(Of aggregate_delegate) =
                                  Sub(ByRef i As aggregate_delegate)
                                      assert(rtn(index) Is Nothing)
                                      assert(Not i Is Nothing)
                                      rtn(index) = i
                                  End Sub
                              If sync_modify_aggregate_command(cmd) Then
                                  [set](sync_modify_aggregate(cmp()))
                              End If
                              If sync_read_modify_aggregate_command(cmd) Then
                                  [set](sync_read_modify_aggregate(cmp()))
                              End If
                              If one_success_aggregate_command(cmd) Then
                                  [set](AddressOf one_result_success_aggregate)
                              End If
                              If all_success_aggregate_command(cmd) Then
                                  [set](AddressOf all_result_success_aggregate)
                              End If
                              If max_div_aggregate_command(cmd) Then
                                  [set](Function(targetJobs() As indexedJob, inputJob As ijob) As Boolean
                                            If redundanceCount() = targetQueues().size() Then
                                                rtn(index) = AddressOf i64_max_aggregate
                                                Return i64_max_aggregate(targetJobs, inputJob)
                                            Else
                                                rtn(index) = AddressOf i64_redundance_divide_aggregate
                                                Return i64_redundance_divide_aggregate(targetJobs, inputJob)
                                            End If
                                        End Function)
                              End If
                              If min_aggregate_command(cmd) Then
                                  [set](AddressOf i64_min_aggregate)
                              End If
                              If sum_aggregate_command(cmd) Then
                                  [set](AddressOf i64_sum_aggregate)
                              End If
                              If rtn(index) Is Nothing Then
                                  rtn(index) = aggregate()
                              End If
                          End Sub)
        Return rtn
    End Function

    Private Function all_aggregate(ByVal targetJobs() As indexedJob, ByVal inputJob As ijob) As Boolean
        Dim offset As Byte = 0
        offset = storageJob(targetJobs(0)).command - job.firstOfStorage
        Return all_aggregators(offset)(targetJobs, inputJob)
    End Function

    Protected Overrides Function aggregate(ByVal targetJobs() As indexedJob, ByVal inputJob As ijob) As Boolean
        assert(valid(inputJob))
        If valid_targetJobs(targetJobs) Then
            If targetJobs.Length() = 1 Then
                Return unique_aggregate(targetJobs, inputJob)
            Else
                Return all_aggregate(targetJobs, inputJob)
            End If
        Else
            Return False
        End If
    End Function
End Class
